﻿using NyARUnityUtils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;

namespace edu.wpi.cs.Project1
{
    /// <summary>
    /// Represents the marker with its appropriate tracked game object.
    /// </summary>
    class TrackedGameObject
    {
        /// <summary>
        /// The AR marker system.
        /// </summary>
        private readonly NyARUnityMarkerSystem markerSystem;

        /// <summary>
        /// The marker ID.
        /// </summary>
        private readonly int markerId;

        /// <summary>
        /// The position for hidden objects.
        /// </summary>
        public readonly Vector3 HIDDEN_POSITION = new Vector3(0, 0, -100);

        /// <summary>
        /// Indicates whether the rotation of the game object should be fixed to the marker
        /// during the update or tracking.
        /// </summary>
        private bool fixRotationToMarker = true;

        /// <summary>
        /// The game object assigned to the marker.
        /// </summary>
        private GameObject gameObject;

        /// <summary>
        /// Creates a new tracked game object instance.
        /// </summary>
        /// <param name="markerSystem">Tha NyARToolkit marker system.</param>
        /// <param name="markerSource">The path or resource name.</param>
        /// <param name="fromResources">If is loaded from the resources or from the assets.</param>
        public TrackedGameObject(NyARUnityMarkerSystem markerSystem, string markerSource, bool fromResources=false)
        {
            this.markerSystem = markerSystem;

            if (fromResources)
            {
                // load from resources
                this.markerId = this.markerSystem.addARMarker(
                    new StreamReader(
                        new MemoryStream(
                            ((TextAsset)Resources.Load(markerSource, typeof(TextAsset))).bytes)),
                    16, 25, 80);
            }
            else
            {
                // load from assets
                this.markerId = this.markerSystem.addARMarker(
                    markerSource,
                    16, 25, 80);
            }
        }

        /// <summary>
        /// Initializes the tracked object
        /// </summary>
        /// <param name="objectName">The name of the game object in Unity3D.</param>
        public void Initialize(string objectName)
        {
            this.gameObject = GameObject.Find(objectName);
        }

        /// <summary>
        /// Updates the tracked object
        /// </summary>
        public void Update()
        {
            // update emitter transform
            if (this.markerSystem.isExistMarker(markerId))
            {
                if (this.FixRotationToMarker)
                {
                    this.markerSystem.setMarkerTransform(markerId, this.GameObject.transform);
                }
                else
                {
                    // keep the object rotation
                    Quaternion prevRotation = this.GameObject.transform.rotation;
                    this.markerSystem.setMarkerTransform(markerId, this.GameObject.transform);
                    this.GameObject.transform.rotation = prevRotation;
                }

                // translate 
                Utility.TranslateToXYLayer(gameObject, GameConfig.POSITION_Z);//Debug.Log("load " + gameObject.name + " !!"); 

                // rotate
                Utility.RotateOrthogonalToXYLayer(gameObject);
            }
            else
            {
                // hide game object
                this.GameObject.transform.localPosition = HIDDEN_POSITION;
            }
        }

        /// <summary>
        /// Gets the tracked game object.
        /// </summary>
        public GameObject GameObject
        {
            get
            {
                return this.gameObject;
            }
        }

        /// <summary>
        /// Gets or sets whether the rotation is fixed to the marker orientation or not.
        /// </summary>
        public bool FixRotationToMarker
        {
            get
            {
                return fixRotationToMarker;
            }
            set
            {
                this.fixRotationToMarker = value;
            }
        }

        /// <summary>
        /// Indicates whether the marker of the tracked game object was detected.
        /// </summary>
        public bool IsDetected
        {
            get
            {
                return this.gameObject.transform.localPosition != HIDDEN_POSITION;
            }
        }
    }
}
